<template>
  <div class="photo">
    <div class="qr-scanner">
      <div class="box">
        <div v-show="isStart" class="line"></div>
        <div class="angle"></div>
        <video
          id="videoCamera"
          class="video-style"
          :width="videoWidth"
          :height="videoHeight"
          autoplay
        />
      </div>
    </div>
    <canvas
      style="display: none"
      id="canvasCamera"
      :width="videoWidth"
      :height="videoHeight"
    />
    <!-- 开始扫码 -->
    <div style="display: flex">
      <div
        v-if="!isStart"
        class="btn-photo"
        @click="
          () => {
            isStart = true;
            this.getCompetence(true);
            startScan(true);
          }
        "
      >
        {{ scanText }}
      </div>
      <div v-if="isStart" class="btn-photo" @click="stopScan()">停止扫码</div>
    </div>
    <img
      v-show="deviceList.length > 1"
      class="icon-style"
      :src="icon"
      @click="changeDevice()"
    />
    <div class="mask"></div>
  </div>
</template>
<script>
import axios from "axios";
import message from "ant-design-vue/lib/message";
import "ant-design-vue/lib/message/style/css";
import QrCode from "../../node_modules/qrcode-decoder/dist/index"; // 解析二维码工具
import Quagga from "quagga"; // ES6  解析条形码

export default {
  name: "camera",
  data() {
    return {
      videoWidth: 300,
      videoHeight: 300,
      isStart: false,
      thisCancas: null,
      thisContext: null,
      thisVideo: null,
      constraints: {
        audio: false,
        video: {},
      },
      deviceList: [],
      isFront: false,
      deviceIndex: 0,
      uploadImgIndex: 0,
      scanText: "开始扫码",
    };
  },
  computed: {
    icon: function () {
      if (this.isFront) return require("../assets/qianzhishexiangtou.svg");
      return require("../assets/houzhishexiangtou.svg");
    },
  },
  mounted() {
    this.getCompetence(true);

    // 测试解析条形码
    var lineCode =
      "";
    let file = URL.createObjectURL(this.dataURLtoFile(lineCode, "aa"));
    console.log(file);
    this.decodeLine(file);

    // 测试解析二维码
    // var image = ''

    // // base64转文件
    // let file = this.dataURLtoFile(image, '文件')
    // // 解析二维码
    // this.decodeQrCode(file)
  },
  methods: {
    changeDevice() {
      if (this.deviceList.length < 2) {
        return;
      }
      if (this.deviceIndex < this.deviceList.length - 1) {
        this.deviceIndex++;
      } else {
        this.deviceIndex = 0;
      }
      let device = this.deviceList[this.deviceIndex];
      this.isFront = !this.isFront;
      this.constraints.video.deviceId = device.deviceId;
      this.getCompetence(false);
    },
    // 调用权限（打开摄像头功能）
    async getCompetence(isInit) {
      return new Promise((resolve, reject) => {
        this.thisCancas = document.getElementById("canvasCamera");
        this.thisContext = this.thisCancas.getContext("2d");
        this.thisVideo = document.getElementById("videoCamera");
        // 旧版本浏览器可能根本不支持mediaDevices，我们首先设置一个空对象
        if (navigator.mediaDevices === undefined) {
          navigator.mediaDevices = {};
        }
        // 一些浏览器实现了部分mediaDevices，我们不能只分配一个对象
        // 使用getUserMedia，因为它会覆盖现有的属性。
        // 这里，如果缺少getUserMedia属性，就添加它。
        if (navigator.mediaDevices.getUserMedia === undefined) {
          navigator.mediaDevices.getUserMedia = (constraints) => {
            // 首先获取现存的getUserMedia(如果存在)
            var getUserMedia =
              navigator.webkitGetUserMedia ||
              navigator.mozGetUserMedia ||
              navigator.getUserMedia;
            // 有些浏览器不支持，会返回错误信息
            // 保持接口一致
            if (!getUserMedia) {
              return Promise.reject(
                new Error("getUserMedia is not implemented in this browser")
              );
            }
            // 否则，使用Promise将调用包装到旧的navigator.getUserMedia
            return new Promise((resolve, reject) => {
              getUserMedia.call(navigator, constraints, resolve, reject);
            });
          };
        }
        //使用此方式获取本地音频视频输入输出设备，找到要使用的设备id，方式见下图
        resolve(navigator.mediaDevices.enumerateDevices());
      })
        .then((devices) => {
          if (devices && Array.isArray(devices)) {
            devices.forEach((device) => {
              if (device.deviceId) {
                if (device.label === "OV5648" || device.label === "GC2355") {
                  this.deviceList.push(device);
                } else if (device.label.toLowerCase().indexOf("audio") === -1) {
                  // 过滤调音频
                  this.deviceList.push(device);
                }
              }
            });
          }
          return navigator.mediaDevices.getUserMedia(this.constraints);
        })
        .then((stream) => {
          // 旧的浏览器可能没有srcObject
          if ("srcObject" in this.thisVideo) {
            this.thisVideo.srcObject = stream;
          } else {
            // 避免在新的浏览器中使用它，因为它正在被弃用。
            this.thisVideo.src = window.URL.createObjectURL(stream);
          }
          this.thisVideo.onloadedmetadata = (e) => {
            this.thisVideo.play();
          };
          return Promise.resolve("success");
        })
        .then(
          (res) => {},
          (err) => {
            console.log("初始化摄像头失败", err);
            if (isInit) {
              alert("初始化摄像头失败");
            } else {
              this.isFront = !this.isFront;
              this.deviceIndex--;
              alert("切换摄像头失败");
            }
          }
        );
    },
    //  绘制图片（拍照功能）
    startScan(isFirst) {
      if (!this.isStart) {
        this.uploadImgIndex = 0;
        return;
      }
      if (isFirst) {
        this.uploadImgIndex = 0;
      } else {
        this.uploadImgIndex++;
      }
      this.scanText = "正在扫码";
      //  注意： 这里其实是绘制image然后上传给服务器的过程
      // 点击，canvas画图
      this.thisContext.drawImage(
        this.thisVideo,
        0,
        0,
        this.videoWidth,
        this.videoHeight
      );
      // 获取图片base64链接
      var image = this.thisCancas.toDataURL("image/png");
      // var image =
      //   "";

      // console.log("绘制得到的图片：", image)
      this.imgSrc = image;
      // base64转文件
      let file = this.dataURLtoFile(image, "文件");
      console.log("文件", file);
      // 解析二维码
      this.decodeQrCode(file);
      // this.uploadImg();
    },
    // 停止扫码
    stopScan() {
      this.isStart = false;
      this.scanText = "开始扫码";
      this.stopNavigator();
    },
    // base64转文件
    dataURLtoFile(dataurl, filename) {
      var arr = dataurl.split(",");
      var mime = arr[0].match(/:(.*?);/)[1];
      var bstr = atob(arr[1]);
      var n = bstr.length;
      var u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, {
        type: mime,
      });
    },
    // 上传图片
    uploadImg() {
      // 这里处理上传图片逻辑
      axios
        .post(
          "/secure/basemodule/business/zrtc/reliable-sample-tasks/action/scan",
          {
            p: { f: { code: this.imgSrc } },
          }
        )
        .then((res) => {
          // 上传成功，停止上传图片，然后关闭此界面，执行后续逻辑
          this.stopNavigator();
          this.isStart = false;
          message.success("识别成功");
        })
        .catch((err) => {
          // 上传失败,而且上传的次数小于三十次，那就一直上传，大于三十次停止上传
          if (this.uploadImgIndex < 50) {
            setTimeout(() => {
              this.startScan();
            }, 200);
          } else {
            this.isStart = false;
            this.scanText = "重新扫码";
            // 大于三十次停止上传, 延迟500ms执行下一次请求
            message.error("识别失败");
            this.stopNavigator();
            console.log("上传了三十次还没成功！！！");
          }
        });
    },
    // 关闭摄像头
    stopNavigator() {
      this.thisVideo.srcObject.getTracks()[0].stop();
    },
    // 解析二维码
    decodeQrCode(file) {
      var url = null;
      if (window.createObjectURL != undefined) {
        //  基础浏览器
        console.log("基础浏览器");
        url = window.createObjectURL(file);
      } else if (window.URL != undefined) {
        //  火狐浏览器
        console.log("火狐浏览器");
        url = window.URL.createObjectURL(file);
      } else if (window.webkitURL != undefined) {
        // 谷歌浏览器
        console.log("谷歌浏览器");
        url = window.webkitURL.createObjectURL(file);
      }
      console.log("url:", url);
      const qr = new QrCode();
      qr.decodeFromImage(url)
        .then((res) => {
          console.log("解析过后数据：", res);
        })
        .catch((err) => {
          console.log("解析失败");
        });
    },
    // 解析条形码
    decodeLine(base64) {
      let config = {
        inputStream: {
          name: "image",
          type: "ImageStream",
          singleChannel: false,
        },
        locator: {
          patchSize: "medium",
          halfSample: false,
        },
        numOfWorkers: 1,
        decoder: {
          readers: ["code_128_reader"],
        },
        locate: true,
        src: base64,
      };
      Quagga.decodeSingle(config, function (result) {
        console.log("条形码", result);
        if (result !== undefined) {
          if (result.codeResult) {
            let message = result.codeResult.code;
            alert(message);
          }
        }
      });
      Quagga.onDetected((res) => {
        console.log("11", res);
      });
    },
  },
  beforeDestroy() {
    this.stopNavigator();
  },
};
</script>

<style scoped>
.photo {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: calc(100%);
  background-color: black;
}

.video-style {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  object-fit: fill;
  z-index: 10;
}

.preview-img {
  display: flex;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

.icon-style {
  position: fixed;
  right: 32px;
  top: 32px;
  cursor: pointer;
  z-index: 30;
}

.btn-photo {
  background-color: rgba(255, 255, 255, 0.6);
  text-align: center;
  padding: 16px 32px;
  border-radius: 10px;
  cursor: pointer;
  font-size: 20px;
  font-weight: bold;
  margin: 0 32px;
  margin-top: 32px;
  z-index: 20;
}

.btn-photo:active {
  opacity: 0.8;
}

.device-container {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
}

.mask {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.4);
}

.qr-scanner {
  background-image: linear-gradient(
      0deg,
      transparent 24%,
      rgba(32, 255, 77, 0.1) 25%,
      rgba(32, 255, 77, 0.1) 26%,
      transparent 27%,
      transparent 74%,
      rgba(32, 255, 77, 0.1) 75%,
      rgba(32, 255, 77, 0.1) 76%,
      transparent 77%,
      transparent
    ),
    linear-gradient(
      90deg,
      transparent 24%,
      rgba(32, 255, 77, 0.1) 25%,
      rgba(32, 255, 77, 0.1) 26%,
      transparent 27%,
      transparent 74%,
      rgba(32, 255, 77, 0.1) 75%,
      rgba(32, 255, 77, 0.1) 76%,
      transparent 77%,
      transparent
    );
  background-size: 3rem 3rem;
  background-position: -1rem -1rem;
  position: relative;
  background-color: #111;
}

.qr-scanner .box {
  width: 300px;
  height: 300px;
  max-height: 300px;
  max-width: 300px;
  position: relative;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  overflow: hidden;
  border: 0.1rem solid rgba(0, 255, 51, 0.2);
  position: relative;
}

.qr-scanner .line {
  height: calc(100% - 2px);
  width: 100%;
  background: linear-gradient(180deg, rgba(0, 255, 51, 0) 43%, #00ff33 211%);
  border-bottom: 3px solid #00ff33;
  transform: translateY(-100%);
  animation: radar-beam 2s infinite;
  animation-timing-function: cubic-bezier(0.53, 0, 0.43, 0.99);
  animation-delay: 1.4s;
  z-index: 11;
  position: relative;
}

.qr-scanner .box:after,
.qr-scanner .box:before,
.qr-scanner .angle:after,
.qr-scanner .angle:before {
  content: "";
  display: block;
  position: absolute;
  width: 20px;
  height: 20px;
  border: 0.2rem solid transparent;
  z-index: 12;
}

.qr-scanner .box:after,
.qr-scanner .box:before {
  top: 0;
  border-top-color: #00ff33;
}

.qr-scanner .angle:after,
.qr-scanner .angle:before {
  bottom: 0;
  border-bottom-color: #00ff33;
}

.qr-scanner .box:before,
.qr-scanner .angle:before {
  left: 0;
  border-left-color: #00ff33;
}

.qr-scanner .box:after,
.qr-scanner .angle:after {
  right: 0;
  border-right-color: #00ff33;
}

@keyframes radar-beam {
  0% {
    transform: translateY(-100%);
  }

  100% {
    transform: translateY(0);
  }
}
</style>
